#include "logger.hpp"
#include <mutex>
#include <sstream>

//初始化静态成员
Logger*Logger::_pInstance=nullptr;
//静态互斥锁 因为单例模式的互斥锁需要对象创立前就存在(保护创建过程)
//也可以保证线程并发时抢夺锁
static std::mutex loggerMUtex; 
Logger::Logger():_root(nullptr),_layout(nullptr),
                _fileAppender(nullptr),_consoleAppender(nullptr),
                _isInitialized(false){
        //初始化在init中完成
}
Logger::~Logger()
{
    if(_root)
    {
        //释放log4pp的资源
        log4cpp::Category::shutdown();
        _root=nullptr;
    }
    //log4cpp的Appender和Layout由系统管理，不需要手动delete
    _layout=nullptr;
    _fileAppender=nullptr;
    _consoleAppender=nullptr;
}
//创建单例日志
Logger* Logger::getInstance()
{
    if(_pInstance==nullptr)
    {
        std::lock_guard<std::mutex>lock(loggerMUtex);
        if(_pInstance==nullptr)
        {
            _pInstance= new Logger();
        }
    }
    return _pInstance;
}
//释放日志
void Logger::destroy()
{
    std::lock_guard<std::mutex>lock(loggerMUtex);
    if(_pInstance!=nullptr)
    {
        delete _pInstance;
        _pInstance=nullptr;
    }
}
bool Logger::init(const std::string &logFilePath)
{
    if(_isInitialized)
    {//
        return true;
    }
    try{
        //创建布局模式，包含时间、优先级、文件名、行号、函数名和日志消息
        // setConversionPattern 是设置格式的核心方法，参数是一个包含格式占位符的字符串。
        // 每个占位符对应一种日志信息，最终会被实际内容替换，具体含义：
        // %d{%Y-%m-%d %H:%M:%S}：日志产生的时间，格式为「年 - 月 - 日 时：分: 秒」（如 2023-10-01 15:30:45）。
        // [%p]：日志级别（Priority），如 DEBUG、INFO、WARN、ERROR（会被方括号包裹，如 [INFO]）。
        // %F：产生日志的源代码文件名（如 User.cpp）。
        // %L：产生日志的代码行号（如 23）。
        // %c：日志类别（通常对应模块或类名，这里是根类别）。
        // %m：用户传入的日志消息内容（如 "用户登录成功"）。
        // %n：换行符，确保每条日志单独占一行
        _layout=new log4cpp::PatternLayout();
        _layout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S} [%p] %F:%L %c - %m%n");

        //创建文件输出器
        _fileAppender=new log4cpp::FileAppender("fileAppnder", logFilePath);
        _fileAppender->setLayout(_layout);

        //创建控制台输出器
        _consoleAppender=new log4cpp::OstreamAppender("consolAppender",&std::cout);
        _consoleAppender->setLayout(_layout);

        //获取日志类比并设置输出器
        _root= &log4cpp::Category::getRoot();
        _root->addAppender(_fileAppender);
        _root->addAppender(_consoleAppender);

        //设置默认优先级为DEBUG
        _root->setPriority(log4cpp::Priority::DEBUG);
        _isInitialized =true;
        return true;
    }
    catch(...)
    {
        std::cerr<<"Failed to initialize logger!"<<std::endl;
        return false;
    }
}
void Logger::warn(const char *file, int line, const char *func, const std::string &msg)
{
    if(!_isInitialized)
    {
        return;
    }
    std::stringstream ss;
    ss<<"["<<file<<":"<<line<<" "<<func<<"]"<<msg;
    _root->warn(ss.str());
}
void Logger::error(const char *file, int line, const char *func, const std::string &msg)
{
    if(!_isInitialized)
    {
        return;
    }
    std::stringstream ss;
    ss<<"["<<file<<":"<<line<<" "<<func<<"]"<<msg;
    _root->error(ss.str());    
}
void Logger::debug(const char *file, int line, const char *func, const std::string &msg)
{
    if(!_isInitialized)
    {
        return;
    }
    std::stringstream ss;
    ss<<"["<<file<<":"<<line<<" "<<func<<"]"<<msg;
    _root->debug(ss.str());
}
void Logger::info(const char *file, int line, const char *func, const std::string &msg)
{
    if(!_isInitialized)
    {
        return;
    }
    std::stringstream ss;
    ss<<"["<<file<<":"<<line<<" "<<func<<"]"<<msg;
    _root->info(ss.str());
}